package redis

import (
	"bluebell/models"
	"encoding/json"
	"strconv"
	"time"

	"go.uber.org/zap"

	"github.com/go-redis/redis"
)

func getIDsFormKey(key string, page, size int64) ([]string, error) {
	start := (page - 1) * size
	end := start + size - 1
	// 3. ZREVRANGE 按分数从大到小的顺序查询指定数量的元素
	return client.ZRevRange(key, start, end).Result()
}

func GetPostIDsInOrder(p *models.ParamPostList) ([]string, error) {
	// 从redis获取id
	// 1. 根据用户请求中携带的order参数确定要查询的redis key
	key := getRedisKey(KeyPostTimeZSet)
	if p.Order == models.OrderScore {
		key = getRedisKey(KeyPostScoreZSet)
	}
	// 2. 确定查询的索引起始点
	return getIDsFormKey(key, p.Page, p.Size)
}

// GetPostVoteData 根据ids查询每篇帖子的投赞成票的数据
func GetPostVoteData(ids []string) (data []int64, err error) {
	//data = make([]int64, 0, len(ids))
	//for _, id := range ids {
	//	key := getRedisKey(KeyPostVotedZSetPF + id)
	//	// 查找key中分数是1的元素的数量->统计每篇帖子的赞成票的数量
	//	v := client.ZCount(key, "1", "1").Val()
	//	data = append(data, v)
	//}
	// 使用pipeline一次发送多条命令,减少RTT
	pipeline := client.Pipeline()
	for _, id := range ids {
		key := getRedisKey(KeyPostVotedZSetPF + id)
		pipeline.ZCount(key, "1", "1")
	}
	cmders, err := pipeline.Exec()
	if err != nil {
		return nil, err
	}
	data = make([]int64, 0, len(cmders))
	for _, cmder := range cmders {
		v := cmder.(*redis.IntCmd).Val()
		data = append(data, v)
	}
	return
}

// GetCommunityPostIDsInOrder 按社区查询ids
func GetCommunityPostIDsInOrder(p *models.ParamPostList) ([]string, error) {
	orderKey := getRedisKey(KeyPostTimeZSet)
	if p.Order == models.OrderScore {
		orderKey = getRedisKey(KeyPostScoreZSet)
	}
	// 使用 zinterstore 把分区的帖子set与帖子分数的 zset 生成一个新的zset
	// 针对新的zset 按之前的逻辑取数据
	// 社区的key
	cKey := getRedisKey(KeyCommunitySetPF + strconv.Itoa(int(p.CommunityID)))
	// 利用缓存key减少zinterstore执行的次数
	key := orderKey + strconv.Itoa(int(p.CommunityID))
	if client.Exists(key).Val() < 1 {
		// 不存在，需要计算
		pipeline := client.Pipeline()
		pipeline.ZInterStore(key, redis.ZStore{
			Aggregate: "MAX",
		}, cKey, orderKey) // zinterstore 计算
		pipeline.Expire(key, 60*time.Second) // 设置超时时间
		_, err := pipeline.Exec()
		if err != nil {
			return nil, err
		}
	}
	// 存在的话就直接根据key查询ids
	return getIDsFormKey(key, p.Page, p.Size)
}

func AddComment(comment *models.Comment) error {
	key := getRedisKey(KeyPostComment + strconv.FormatInt(comment.CommentID, 10))
	// 序列化评论对象
	data, err := json.Marshal(comment)
	if err != nil {
		zap.L().Error("AddComment json.Marshal(comment) error", zap.Error(err))
		return err
	}
	// 将评论存储到Redis中，使用有序集合存储，以评论时间为分数
	if _, err := client.ZAdd(key, redis.Z{Score: float64(comment.CreateTime), Member: data}).Result(); err != nil {
		zap.L().Error("AddComment client.ZAdd error", zap.Error(err))
		return err
	}
	return nil
}
func GetComments(postID int64) ([]*models.Comment, error) {
	key := getRedisKey(KeyPostComment + strconv.FormatInt(postID, 10))
	// 获取有序集合中的所有成员
	data, err := client.ZRange(key, 0, -1).Result()
	if err != nil {
		zap.L().Error("GetComments client.ZRange error", zap.Error(err))
		return nil, err
	}

	// 反序列化每个成员到 Comment 结构体
	var comments []*models.Comment
	for _, item := range data {
		var comment models.Comment
		if err := json.Unmarshal([]byte(item), &comment); err != nil {
			zap.L().Error("GetComments json.Unmarshal error", zap.Error(err))
			continue
		}
		comments = append(comments, &comment)
	}

	return comments, nil
}
